window.onload = function() {
	asdasd.render(document.body);
};

// create the overall containing object
asdasd = {
	// create the inner panel
	Panel: {
		// the panel element
		el: document.createElement('panel'),

		// the inventory that will contain parts
		Inventory: {
			// the inventory element
			el: document.createElement('inventory'),

			// the title of the inventory
			Title: {
				// the title element
				el: document.createElement('title'),

				/**
				 *
				 **/
				render: function(parent) {
					// save the controlled to the element
					this.el.controller = this;

					// save the parent to the object and render the element
					(this.parent = parent).el.appendChild(this.el);

					// adjust the inner html
					this.el.innerHTML = 'Inventory';
				}
			},

			// the dragger that allows parts to be moved around
			Parts: {
				//
				el: document.createElement('parts'),

				// the list of parts
				list: [],

				// the currently selected elements
				selected: [],

				// the selector that allows parts to be dragged around
				Selector: {
					//
					el: document.createElement('selector'),

					// the elements the selector has selected
					selected: [],

					/**
					 *
					 **/
					getSelected: function() {
						// get all the selected parts
						for (var element in this.parent.selected) {
							// save the next sibling
							this.parent.selected[element].nextSibling = this.parent.selected[element].el.nextSibling;

							// push the element onto the selected
							this.selected.push(this.parent.selected[element]);

							// append to the selector
							this.el.appendChild(this.parent.selected[element].el);
						}
					},

					/**
					 *
					 **/
					hide: function() {
						this.el.style.visibility = 'hidden';
					},

					/**
					 *
					 **/
					isVisible: function() {
						return this.el.style.visibility == 'visible';
					},

					/**
					 *
					 **/
					moveTo: function(x, y) {
						this.el.style.top = y;
						this.el.style.left = x;
					},

					/**
					 *
					 **/
					render: function(parent) {
						// save the controlled to the element
						this.el.controller = this;

						// save the parent to the object and render the element
						(this.parent = parent).el.appendChild(this.el);
					},

					/**
					 *
					 **/
					returnSelected: function() {
						// get all the selected parts
						for (var size = this.selected.length - 1; size >= 0; size --) {
							// insert back into inventory
							this.parent.el.insertBefore(this.selected[size].el, this.selected[size].nextSibling);

							// delete the saved next sibling
							delete this.selected[size].nextSibling;

							// remove the element from the array
							this.selected.splice(size, 1);
						}
					},

					/**
					 *
					 **/
					show: function() {
						this.el.style.visibility = 'visible';
					}
				},

				/**
				 *
				 **/
				createPart: function() {
					// render a new part
					return new this.part().render(this);
				},

				/**
				 *
				 **/
				drag: function(event) {
					// only move selector when visible
					if (this.Selector.isVisible()) {
						// move the selector
						this.Selector.moveTo(parseInt(this.Selector.el.style.left) + event.x - this.mouseLocation.x, parseInt(this.Selector.el.style.top) + event.y - this.mouseLocation.y);

						// update mouse location
						this.mouseLocation = { x: event.x, y: event.y };
					}
				},

				/**
				 *
				 **/
				dragDrop: function(event) {

					// reset the click delay
					clearTimeout(this.dragId);

					// make sure selector is visible
					if (this.Selector.isVisible()) {
						// hide the selector
						this.Selector.hide();

						// return the elements to the inventory
						this.Selector.returnSelected();
					}
				},

				/**
				 *
				 **/
				dragStart: function(event) {
					var target = event.toElement;

					if (target.controller.isSelected && target.controller.isSelected()) {
						// create the drag identifier
						this.dragId = setTimeout(function() {

							// get the current mouse location
							this.mouseLocation = { x: event.x, y: event.y };

							// move the selector to the correct location
							this.Selector.moveTo(event.x - 42, event.y - 5);

							// get the selected elements
							this.Selector.getSelected();

							// show the selector
							this.Selector.show();

						}.bind(this), 200);
					}
				},

				/**
				 *
				 **/
				part: function() {

					this.el = document.createElement('part');

					this.Quantity = {
						el: document.createElement('quantity'),

						/**
						 *
						 **/
						render: function(parent) {
							// save the controlled to the element
							this.el.controller = this;

							// save the parent to the object and render the element
							(this.parent = parent).el.appendChild(this.el);

							// assign a random quantity vaue
							this.el.innerHTML = Math.floor(Math.random() * 80);
						}
					};

					/**
					 *
					 **/
					this.delete = function() {
						// delete the element
						this.el.parentElement.removeChild(this.el);

						// remove the item from total list
						removeByValue(this.parent.list, this);

						// remove it from the selected list
						removeByValue(this.parent.selected, this);
					};

					/**
					 *
					 **/
					this.isSelected = function() {
						// check if the part is currently selected
						return this.el.classList.contains('selected');
					};

					/**
					 *
					 **/
					this.offset = function() {
						// initialize the element and current offset
						var element = this.el, x = y = 0;

						// calculate the offset
						do {
							x += element.offsetLeft;
							y += element.offsetTop;
						}
						while (element = element.offsetParent);

						return { x: x, y: y };
					};

					/**
					 *
					 **/
					this.render = function(parent) {
						// save the controlled to the element
						this.el.controller = this;

						// save the parent to the object and render the element
						(this.parent = parent).el.appendChild(this.el);

						// render the quantity field
						this.Quantity.render(this);

						// add the item to the list
						this.parent.list.push(this);

						// listeners for the element
						this.parent.parent.parent.el.onmouseup = this.parent.dragDrop.bind(this.parent);
						this.parent.parent.parent.el.onmousemove = this.parent.drag.bind(this.parent);
						this.el.onmousedown = this.parent.dragStart.bind(this.parent);
						this.el.onclick = this.parent.selectPart.bind(this.parent);
					};

					/**
					 *
					 **/
					this.select = function() {
						// make sure part has not been previously selected
						if (!this.isSelected()) {
							// add the selected class
							this.el.classList.add('selected');

							// add it to the selected list
							this.parent.selected.push(this);
						}
					};

					/**
					 *
					 **/
					this.toggleSelect = function(force) {
						typeof force == 'boolean' ? (force ? this.select() : this.unselect()) : (this.isSelected() ? this.unselect() : this.select());
					};

					/**
					 *
					 **/
					this.unselect = function() {
						// make sure part has been previously selected
						if (this.isSelected()) {
							// add the selected class
							this.el.classList.remove('selected');

							// add it to the selected list
							removeByValue(this.parent.selected, this);
						}
					};
				},

				/**
				 *
				 **/
				removePart: function() {
					// remove the selected items
					for (var index = this.selected.length - 1; index >= 0; index --) {
						this.selected[index].delete();
					}
				},

				/**
				 *
				 **/
				render: function(parent) {
					// save the controlled to the element
					this.el.controller = this;

					// save the parent to the object and render the element
					(this.parent = parent).el.appendChild(this.el);

					// render the selector
					this.Selector.render(this);
				},

				/**
				 *
				 **/
				selectPart: function(event) {
					// get the target
					var target = event.toElement;

					// make sure this only targets parts
					if (target.tagName == 'PART') {
						// highlight a range of parts with shift key pressed
						if (event.shiftKey) {
							// get the last element that was clicked
							!this.pivotElement && (this.pivotElement = this.selected[this.selected.length - 1] || target.controller);

							// unselect all the parts
							this.unselectAll();

							// elements are the same
							if (target.offsetTop == this.pivotElement.el.offsetTop) {
								// select the pivot element
								this.pivotElement.select();
							}

							// needs to select downwards
							else if (target.offsetTop > this.pivotElement.el.offsetTop) {
								// get the current element
								var currentElement = this.pivotElement.el;

								// select everything until the target
								do {
									currentElement.controller.select();
								}

								while (currentElement && (currentElement = currentElement.nextSibling) != target.nextSibling);
							}

							// needs to select upwards
							else {
								// get the current element
								var currentElement = this.pivotElement.el;

								// select everything until the target
								do {
									currentElement.controller.select();
								}

								while (currentElement && (currentElement = currentElement.previousSibling) != target.previousSibling);
							}
						}

						// highlight specific parts with control key pressed
						else if (event.metaKey) {
							// toggle the selection status of the part
							target.controller.toggleSelect();

							// reset the pivot element
							this.pivotElement && delete this.pivotElement;
						}

						// unselect all and highlight the current target
						else {
							// unselect all the parts
							this.unselectAll();

							// toggle selection of the current target
							target.controller.select();

							// reset the pivot element
							this.pivotElement && delete this.pivotElement;
						}
					}
				},

				/**
				 *
				 **/
				unselectAll: function() {
					// unselect all the parts
					for (var index = this.selected.length - 1; index >= 0; index --) {
						this.selected[index].unselect();
					}
				}
			},

			// the buttons that will allow creating and removing of parts
			Buttons: {
				// the button container element
				el: document.createElement('buttons'),

				// the part adding button
				Add: {
					// the create part button
					el: document.createElement('button'),

					/**
				 	 *
				 	 **/
					render: function(parent) {
						// save the controlled to the element
						this.el.controller = this;

						// save the parent to the object and render the element
						(this.parent = parent).el.appendChild(this.el);

						// adjust the class
						this.el.classList.add('add');

						// adjust the inner html
						this.el.innerHTML = '+';

						// listeners for the button
						this.el.onclick = this.parent.parent.Parts.createPart.bind(this.parent.parent.Parts);
					}
				},

				// the part removing button
				Remove: {
					//
					el: document.createElement('button'),

					/**
					 *
					 **/
					render: function(parent) {
						// save the controlled to the element
						this.el.controller = this;

						// save the parent to the object and render the element
						(this.parent = parent).el.appendChild(this.el);

						// adjust the class
						this.el.classList.add('remove');

						// adjust the inner html
						this.el.innerHTML = '-';

						// listeners for the button
						this.el.onclick = this.parent.parent.Parts.removePart.bind(this.parent.parent.Parts);
					}
				},

				/**
				 *
				 **/
				render: function(parent) {
					// save the controlled to the element
					this.el.controller = this;

					// save the parent to the object and render the element
					(this.parent = parent).el.appendChild(this.el);

					this.Add.render(this);
					this.Remove.render(this);
				}
			},

			/**
			 *
			 **/
			render: function(parent) {
				// save the controlled to the element
				this.el.controller = this;

				// save the parent to the object and render the element
				(this.parent = parent).el.appendChild(this.el);

				this.Title.render(this);
				this.Parts.render(this);
				this.Buttons.render(this);
			}
		},
		Mod: {
			//
			el: document.createElement('mod'),

			/**
			 *
			 **/
			render: function(parent) {
				// save the controlled to the element
				this.el.controller = this;

				// save the parent to the object and render the element
				(this.parent = parent).el.appendChild(this.el);
			}
		},

		/**
		 *
		 **/
		render: function(parent) {
			// save the controlled to the element
			this.el.controller = this;

			// save the parent to the object and render the element
			(this.parent = parent).el.appendChild(this.el);

			// render the inventory and mod containers
			this.Inventory.render(this);
			this.Mod.render(this);
		}
	},

	/**
	 *
	 **/
	render: function(element) {
		// save the element that the object will be rendered to
		this.el = element;

		// render the panel to the screen
		this.Panel.render(this);

		// listeners for the element
		document.onselectstart = function() { return false; };
	}
};

removeByValue = function(array, value) {
	for (var index = 0; index < array.length; index ++) {
		if (array[index] === value && array.splice(index, 1)) {
			break;
		}
	}
};